package com.xiaouyudeguang.common.api;

import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaouyudeguang.common.annotation.ApiMapping;
import com.xiaouyudeguang.common.annotation.TableCache;
import com.xiaouyudeguang.common.cache.RedisCache;
import com.xiaouyudeguang.common.constants.Headers;
import com.xiaouyudeguang.common.request.RequestDto;
import com.xiaouyudeguang.common.respose.ResultDto;
import com.xiaouyudeguang.common.utils.JsonObject;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public interface AbstractApi<T> extends BaseApi {

    @ApiMapping(value = "/getById/{id}", method = RequestMethod.GET, tags = "根据id查询")
    ResultDto<T> getById(@RequestHeader(Headers.TENANT_ID) String tenantId,
                         @RequestHeader(Headers.APP_ID) String appId,
                         @PathVariable("id") String id) throws Exception;

    @ApiMapping(value = "/cacheById/{id}", method = RequestMethod.GET, tags = "根据从缓存获取")
    default ResultDto<T> cacheById(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                   @RequestHeader(Headers.APP_ID) String appId,
                                   @RequestHeader(name = Headers.FROM) String from,
                                   @PathVariable("id") String id) throws Exception {
        Class<T> modelClass = currentModelClass();
        String cacheKey = modelClass.getName() + tenantId + ":" + appId + ":" + id;
        String cacheValue = RedisCache.get(cacheKey);
        if (isBlank(cacheValue)) {
            T data = ResultDto.getResult(getById(tenantId, appId, id));
            cacheValue = data == null ? "" : JsonObject.toJson(data);
            TableCache cache = modelClass.getAnnotation(TableCache.class);
            if (cache != null) {
                RedisCache.set(cacheKey, cacheValue, cache.value(), cache.unit());
            } else {
                RedisCache.set(cacheKey, cacheValue, 15, TimeUnit.SECONDS);
            }
        }
        return isBlank(cacheValue) ? ResultDto.ok() : ResultDto.ok(JsonObject.fromJson(cacheValue, modelClass));
    }

    default Class<T> currentModelClass() {
        return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), AbstractApi.class, 0);
    }

    @ApiMapping(method = RequestMethod.POST, tags = "根据id批量查询", value = "/getByIds")
    ResultDto<List<T>> getByIds(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                @RequestHeader(Headers.APP_ID) String appId,
                                @RequestBody Set<String> ids) throws Exception;

    @ApiMapping(value = "/deleteById/{id}", method = RequestMethod.DELETE, tags = "根据id删除")
    ResultDto<Boolean> deleteById(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                  @RequestHeader(Headers.APP_ID) String appId,
                                  @PathVariable("id") String id) throws Exception;

    @ApiMapping(value = "/deleteByIds", method = RequestMethod.DELETE, tags = "根据id批量删除")
    ResultDto<Boolean> deleteByIds(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                   @RequestHeader(Headers.APP_ID) String appId,
                                   @RequestBody Set<String> ids) throws Exception;

    @ApiMapping(value = "/updateById", method = RequestMethod.PUT, tags = "根据id更新")
    ResultDto<Boolean> updateById(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                  @RequestHeader(Headers.APP_ID) String appId,
                                  @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/updateByIds", method = RequestMethod.PUT, tags = "根据id批量更新")
    ResultDto<Boolean> updateByIds(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                   @RequestHeader(Headers.APP_ID) String appId,
                                   @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/updateBatch", method = RequestMethod.PUT, tags = "批量更新")
    ResultDto<Boolean> updateBatch(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                   @RequestHeader(Headers.APP_ID) String appId,
                                   @RequestBody List<T> dataList) throws Exception;

    @ApiMapping(value = "/modify", method = RequestMethod.PUT, tags = "修改")
    ResultDto<Boolean> modify(@RequestHeader(Headers.TENANT_ID) String tenantId,
                              @RequestHeader(Headers.APP_ID) String appId,
                              @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/save", method = RequestMethod.POST, tags = "保存")
    ResultDto<Boolean> save(@RequestHeader(Headers.TENANT_ID) String tenantId,
                            @RequestHeader(Headers.APP_ID) String appId,
                            @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/saveAndGet", method = RequestMethod.POST, tags = "保存或查询")
    ResultDto<T> saveAndGet(@RequestHeader(Headers.TENANT_ID) String tenantId,
                            @RequestHeader(Headers.APP_ID) String appId,
                            @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/saveBatch", method = RequestMethod.POST, tags = "批量保存")
    ResultDto<Boolean> saveBatch(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                 @RequestHeader(Headers.APP_ID) String appId,
                                 @RequestBody List<T> dataList) throws Exception;

    @ApiMapping(value = "/getOne", method = RequestMethod.POST, tags = "单条查询")
    ResultDto<T> getOne(@RequestHeader(Headers.TENANT_ID) String tenantId,
                        @RequestHeader(Headers.APP_ID) String appId,
                        @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/exist", method = RequestMethod.POST, tags = "存在校验")
    ResultDto<Boolean> exist(@RequestHeader(Headers.TENANT_ID) String tenantId,
                             @RequestHeader(Headers.APP_ID) String appId,
                             @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/list", method = RequestMethod.POST, tags = "列表查询")
    ResultDto<List<T>> list(@RequestHeader(Headers.TENANT_ID) String tenantId,
                            @RequestHeader(Headers.APP_ID) String appId,
                            @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/tree", method = RequestMethod.POST, tags = "树形查询")
    ResultDto<List<T>> tree(@RequestHeader(Headers.TENANT_ID) String tenantId,
                            @RequestHeader(Headers.APP_ID) String appId,
                            @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(method = RequestMethod.POST, tags = "查询所有数据", value = "/listAll")
    ResultDto<List<T>> listAll(@RequestHeader(Headers.TENANT_ID) String tenantId,
                               @RequestHeader(Headers.APP_ID) String appId,
                               @RequestHeader(name = Headers.FROM) String from) throws Exception;

    @ApiMapping(method = RequestMethod.POST, tags = "查询所有数据id", value = "/listAllIds")
    ResultDto<Set<String>> listAllIds(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                      @RequestHeader(Headers.APP_ID) String appId,
                                      @RequestHeader(name = Headers.FROM) String from) throws Exception;

    @ApiMapping(value = "/count", method = RequestMethod.POST, tags = "统计总数(后端)")
    ResultDto<Long> count(@RequestHeader(Headers.TENANT_ID) String tenantId,
                                     @RequestHeader(Headers.APP_ID) String appId,
                                     @RequestHeader(name = Headers.FROM) String from,
                                     @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/page", method = RequestMethod.POST, tags = "分页查询(前端)")
    ResultDto<Object> page(@RequestHeader(Headers.TENANT_ID) String tenantId,
                           @RequestHeader(Headers.APP_ID) String appId,
                           @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/pageAll", method = RequestMethod.POST, tags = "分页查询(后端)")
    ResultDto<Page<T>> pageAll(@RequestHeader(Headers.TENANT_ID) String tenantId,
                               @RequestHeader(Headers.APP_ID) String appId,
                               @RequestHeader(name = Headers.FROM) String from,
                               @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/export", method = RequestMethod.POST, tags = "数据导出")
    void export(@RequestHeader(Headers.TENANT_ID) String tenantId,
                @RequestHeader(Headers.APP_ID) String appId,
                @RequestBody RequestDto<T> requestDto) throws Exception;

    @ApiMapping(value = "/upload", method = RequestMethod.POST, tags = "数据导入")
    ResultDto<Object> upload(@RequestHeader(Headers.TENANT_ID) String tenantId,
                             @RequestHeader(Headers.APP_ID) String appId,
                             MultipartFile file) throws Exception;
}
